package rua.jose.macamo;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.AttributeSet;
import android.view.View;

/**
 * This class takes care of listening to sensor events for the compass and drawing the compass
 * @author Panu Parviainen
 *
 */
public class CompassView extends View implements SensorEventListener{
   private SensorManager mSensorManager;
   private Sensor mSensor;
   private Bitmap needle;
   private Bitmap compassbase;
   private final Matrix rotateMatrix = new Matrix();
   private float[] mValues;
   private boolean firstRun;
   protected float angle;
   private float screenCenterX, screenCenterY;
   private float compassX, compassY;
   private float bmCenterX, bmCenterY;
   private final Paint paint = new Paint();

   /**
    * Constructor for CompassView
    * @param context Context from the activity where this View is initiliazed
    */
   public CompassView(final Context context){
      super(context);
      init(context);
   }

   /**
    * Constructor for CompassView, takes also settings as parameter
    * @param context Context from the activity where this View is initialized
    * @param as AttributeSet which contains the settings for this view
    */
   public CompassView(final Context context, final AttributeSet as){
      super(context, as);
      init(context);
   }

   /**
    * Initializes all required components for this view ie. starts listening to sensors,
    * and gets the images for compass needle and background
    * @param context Context from the activity where this View is initiliazed
    */
   public void init(final Context context){
      mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
      mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);

      this.needle = BitmapFactory.decodeResource(context.getResources(),R.drawable.compassneedle);
      this.compassbase = BitmapFactory.decodeResource(context.getResources(),R.drawable.compassbase);
      this.firstRun = true;
      this.angle = 0;
   }

   @Override
   public void setVisibility(final int visibility) {
      if (visibility == View.VISIBLE) {
         mSensorManager.unregisterListener(this); //Unregister the possible previous listener
         mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_GAME); //re-register
      }
      else if (visibility == View.INVISIBLE || visibility == View.GONE)
         mSensorManager.unregisterListener(this);
      super.setVisibility(visibility);
   }

   @Override
   protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec){
      this.setMeasuredDimension(compassbase.getHeight(), compassbase.getHeight());
   }

   @Override
   public void onDraw(final Canvas c) {
      if(firstRun){
         screenCenterX = getWidth() / 2f;
         screenCenterY = getHeight() / 2f;
         bmCenterX = needle.getWidth() / 2f;
         bmCenterY = needle.getHeight() / 2f;
         compassX = screenCenterX-compassbase.getWidth()/2f;
         compassY = screenCenterY-compassbase.getHeight()/2f;
         firstRun = false;
      }
      c.drawColor(Color.TRANSPARENT);
      paint.setAlpha(255); //0-255
      c.drawBitmap(compassbase, compassX, compassY, paint);
      c.translate(screenCenterX-bmCenterX, screenCenterY- bmCenterY);
      rotateMatrix.reset();
      if(mValues != null){
         rotateMatrix.setRotate((-mValues[0]-angle),bmCenterX, bmCenterY);
      }
      paint.setAlpha(230); //0-255
      c.drawBitmap(needle, rotateMatrix, paint);
   }

   /**
    * Takes care of sensor change.
    */
   public void onSensorChanged(final SensorEvent event) {
      mValues = event.values;
      if(this != null){
         invalidate();
      }
   }

   public void onAccuracyChanged(final Sensor sensor, final int accuracy) {}
}
